Перейти к основному содержимому

4.07. Парадигмы и уровни абстракции

Разработчику Архитектору Инженеру

Парадигма

Что такое парадигма?

Парадигма — это философия написания кода. Как мы видим задачу - как набор команд, вычисления, объекты, потоки событий.

Словом, здесь речь не о синтаксисе, а о логике и структуре, о том, как организуется мысль.

Соответственно, парадигмы это не правила, а инструменты восприятия.

Почему так важно именно мышление? Потому что мы можем выучить ключевые слова, возможности языка и различные варианты решения проблем, но фундаментально важно именно то, как мы их применим, какие комбинации, алгоритмы и хитрости используем.

У разных команд, разных разработчиков и разных специалистов свои взгляды на одно и то же - это порождает споры и рассуждения о «великом», о том, как лучше.

К примеру, что делать сначала и в каком порядке, что и как мы хотим получать.

Основные парадигмы

Часто у новичка может возникнуть сложность при изучении ООП. Но мы постараемся разобраться, одновременно нагружая теорией и закрепляя пониманием.

Так, мы поняли, что такое код, блоки кода, функции, программы, компиляция и интерпретация. Мы понимаем, что есть набор кода – ключевых слов, операций, операндов и условных операторов. Мы изучили в JavaScript и SQL основы функций – когда выполняется какая-то операция, возвращающая результат.

Мы определили, что процесс написания кода (программы) называется программированием. Но оно не ограничено только выбором языка. Важную роль играет то, как взаимодействуют элементы, формулируется логика, как описываются и выполняются задачи. Программирование осуществляется с соблюдением правил, установленных парадигмами программирования. Один язык может позволять писать с использованием разных парадигм. Ключевое для программиста - знание ООП, но мы вкратце посмотрим и на другие виды.

  1. Императивное программирование — это парадигма, которая фокусируется на описании последовательности действий (команд), которые компьютер должен выполнить для достижения результата. Это характерно для языков C, Pascal, Fortran, Assembly. Пример:
начало
a = 5
b = 10
c = a + b
вывод(c)
конец
  1. Функциональное программирование - парадигма, где программа строится как набор математических функций. Акцент делается на вычислениях без изменения состояния. Языки - Haskell, Lisp, F#, Scala, Python (частичная поддержка). Пример:
функция сумма(список):
если список пустой:
вернуть 0
иначе:
вернуть первый элемент + сумма(остальные элементы)

начало
числа = [1, 2, 3, 4]
результат = сумма(числа)
вывод(результат)
конец
  1. Логическое программирование - парадигма, основанная на формальной логике. Программа состоит из фактов и правил, а компьютер решает задачи, выводя новые факты. Здесь пишется «что» нужно делать, а не «как». Языки - Prolog, Datalog, Mercury.

Пример:

факт: родитель(джон, джим)
факт: родитель(джим, энн)

правило: предок(X, Y) если родитель(X, Y)
правило: предок(X, Y) если родитель(X, Z) и предок(Z, Y)

запрос: предок(джон, энн)
  1. Процедурное программирование - подвид императивного программирования, где программа разбивается на процедуры (функции или подпрограммы). Языки - C, Pascal, BASIC, Fortran. Пример:
процедура привет():
вывод("Привет, мир!")

начало
привет()
конец
  1. Декларативное программирование - парадигма, где программа описывает желаемый результат, а не последовательность действий для его достижения. Здесь меньше внимания уделяется деталям реализации. Языки - SQL, HTML, CSS, Haskell (частично декларативный). Пример:
запрос:
выбрать имя, возраст из пользователи где возраст > 18
  1. Аспектно-ориентированное программирование (АОП) фокусируется на разделении «поперечных» (cross-cutting) аспектов программы (например, логирование, обработка ошибок) от основной бизнес-логики. Тут имеет место уменьшение дублирования кода и разделение кода на модули, которые можно комбинировать. Языки - AspectJ, Spring AOP (Java), PostSharp (.NET). Пример:
аспект логирование:
перед выполнением метода:
записать в журнал("Метод вызван")

класс пример:
метод действие():
вывод("Действие выполнено")

AOP подразумевает, что сквозная логика отделяется от основной бизнес-логики.

Сквозная логика — это функционал, который повторяется во многих местах приложения. Вместо того чтобы дублировать такой код в каждом методе, AOP позволяет вынести его в отдельные модули — аспекты — и применять их автоматически с помощью pointcuts, которые определяют, где именно аспект должен сработать.

  1. Событийно-ориентированное программирование - программа реагирует на события, такие как действия пользователя, сигналы системы или сообщения от других программ. Широко используется в графических интерфейса. Языки - JavaScript, C#, Qt (C++), Python (Tkinter). Пример:
событие нажатие_кнопки:
вывод("Кнопка нажата!")

начало
добавить_обработчик(кнопка, нажатие_кнопки)
конец
  1. Параллельное и конкурентное программирование - фокус на выполнении нескольких задач одновременно (параллельно) или с переключением контекста (конкурентно). Это нужно при управлении синхронизацией и общими ресурсами. Языки - Erlang, Go, Python (модуль threading), Java (в части многопоточности). Пример:
поток A:
повторять:
вывод("Поток A")

поток B:
повторять:
вывод("Поток B")

начало
запустить(A)
запустить(B)
конец
  1. Метапрограммирование - написание программ, которые могут создавать или модифицировать другие программы (включая самих себя). Здесь имеет место генерация кода во время выполнения. Языки - Ruby, Python, Lisp, C++. Пример:
функция создать_функцию(n):
вернуть функция(x):
вернуть x + n

начало
f = создать_функцию(5)
вывод(f(10)) // Вывод: 15
конец
  1. Реактивное программирование ориентировано на работу с потоками данных и автоматическое распространение изменений. Данные представляются в виде потоков (data streams, например, события UI, HTTP-запросы, сообщения чата), и могут быть бесконечными (курс валют) или конечными (один запрос-ответ). При изменении данных система автоматически обновляет зависимые вычисления (без явного управления состоянием) — это и есть реактивность. Программист описывает, что должно происходить, а не как, так что это близко к декларативному программированию. Используется для упрощения асинхронного кода, чистой обработки событий, эффективного управления состоянием.

  2. ООП – объектно-ориентированное программирование. Представим, что мы пишем код не просто как набор функций и переменных, а как взаимодействие объектов. Как в реальном мире. ООП позволяет структурировать код, делая его понятнее, уменьшает дублирование (один раз описал класс – используешь много раз), облегчает модификацию и расширение кода, и позволяет моделировать реальные сущности (пользователь, товар, заказ).

Смешанные стили

Выбрав язык, мы не придерживаемся строго определенной парадигмы.
Как смешиваются стили
Смешанные стили программирования
Почти все современные языки - мультипарадигменные.
Python: ООП + функциональное + императивное + метапрограммирование.
JavaScript: императивное + функциональное + событийное + реактивное.
Java: ООП + АОП (через Spring) + частично функциональное (лямбды).

Примеры смешения:
В ООП-классе используешь функциональные методы (например, map, filter).
В декларативном React пишешь императивные обработчики событий.
В параллельной системе на Go — используешь событийную логику для обмена сообщениями.

Уровни абстракции

Что такое абстракция?
Абстракция — это скрытие деталей.
Абстрактное мышление
Абстракция вне ООП, в части программирования в целом
Уровни абстракции (среди них метапрограммирование)
Чем выше уровень — тем дальше от железа, ближе к человеческому мышлению.

Уровни:

Машина — биты, байты, регистры (ассемблер).
Процедуры — функции, циклы, переменные (C).
Объекты — классы, наследование, инкапсуляция (Java, Python).
Фреймворки — готовые структуры (Django, React, Spring).
Метауровень — код, который управляет кодом.

Метапрограммирование

Что такое метауровень
Это уровень, на котором программа анализирует, изменяет или генерирует другой код.
Что такое метапрограммирование
Когда использовать
Метапрограммирование - что оно создает - фреймворки, транспайлеры, генераторы кода.
Метапрограммирование в прогарммировании - декораторы, аннотации, ORM, макросы, рефлексия
Метапрограммирование на этапе компиляции (макросы, генерация кода)
Метапрограммирование на этапе выполнения (рефлексия, динамическое создание объектов)